# Replication script for "When Do International Organizations Engage in Agency Slack?
# A Qualitative Comparative Analysis of United Nations Institutions", Global Studies Quarterly (2022),
# by Eugénia C. Heldt, Patrick A. Mello, Anna Novoselova, & Omar Ramon Serrano Oswald
# https://doi.org/10.1093/isagsq/ksac035

# Corresponding Author R Script: Patrick A. Mello
# Website: https://patrickmello.com
# E-mail: mello@hfp.tum.de

# Load Packages
library(QCA); library(SetMethods)

# Read Data
slack <- read.csv("GSQ Heldt et al replication data.csv", header = TRUE, row.names = 1, sep = ";")

# Necessary Condition Analysis (Table A2)
QCAfit(slack[, 1:4], slack$AS, necessity = TRUE, neg.out = FALSE)
QCAfit(slack[, 1:4], slack$AS, necessity = TRUE, neg.out = TRUE)

# Conservative Solution
TT <- truthTable(slack, outcome = "AS", conditions = "D, S, P, M",
                    complete = TRUE, show.cases = TRUE, 
                    sort.by = c("incl", "n"), incl.cut = 0.90)
TT #(Table 2)

SOLcs <- minimize(TT, outcome = "AS",include = "1", row.dom = FALSE,
                    details = TRUE, show.cases = TRUE, use.tilde = TRUE,
                    all.sol = TRUE, method = "CCubes")
SOLcs #(Table 3)

slack$SOLcs <- compute("S*P+D*S*M", data = slack, separate = FALSE)

# XY Plot (Figure)

# Create data for shaded area for typical cases
poly <- data.frame(x = c(0.5, 0.5, 1.1), y = c(0.5, 1.1, 1.1))
geom_polygon(inherit.aes = FALSE, aes(x = x, y = y), data = poly,
              fill = "gray87", alpha = 0.4)

# Plot Conservative Solution Term
UNACC <- slack[c("IMO", "UNODC"),] # Subsets of unaccounted cases
TYP <- subset(slack, AS > 0.5 & SOLcs > 0.5) # Subset of covered cases
TYP1 <- slack[c("ILO", "UNIDO", "UPU"),] # Subsets of covered cases
TYP2 <- slack[c("UNWTO1", "WHO"),]
TYP3 <- slack[c("UNESCO", "UNCTAD"),]
TYP4 <- slack[c("ITU", "WIPO"),]
IRR1 <- slack[c("UNOPS", "ICAO", "WFP"),] # irrelevant cases 1
IRR2a <- slack[c("UNWTO2"),] # irrelevant cases 2a
IRR2b <- slack[c("FAO"),] # irrelevant cases 2b
IRR2c <- slack[c("IAEA"),] # irrelevant cases 2b

CS <- ggplot(slack, aes(x = SOLcs, y = AS)) +
  geom_polygon(inherit.aes = FALSE, aes(x = x, y = y), data = poly,
        fill = "gray95") + 
  geom_point(data = UNACC, fill = "gray70", size = 7, shape = 21,
             color = "black", stroke = 1) +
  geom_point(data = IRR1, fill = "gray70", size = 7, shape = 21,
        color = "black", stroke = 1) +
  geom_point(data = IRR2a, fill = "gray70", size = 7, shape = 21,
             color = "black", stroke = 1,
             position = position_jitter(width = 0.01, height = 0.01)) +
  geom_point(data = IRR2b, fill = "gray70", size = 7, shape = 21,
             color = "black", stroke = 1,
             position = position_jitter(width = 0.01, height = 0.01)) +
  geom_point(data = IRR2c, fill = "gray70", size = 7, shape = 21,
             color = "black", stroke = 1,
             position = position_jitter(width = 0.01, height = 0.01)) +
  geom_point(data = TYP, fill = "dodgerblue", size = 7, shape = 21,
        color = "black", stroke = 1, 
        position = position_jitter(width = 0.01, height = 0.01)) +
        scale_x_continuous(name = "Solution Term (S*P + D*S*M)",
            breaks = seq(0.0,1.0,0.1)) +
        scale_y_continuous(name = "Agency Slack", 
            breaks = seq(0.0,1.0,0.1)) +
        coord_cartesian(xlim = c(-0.02,1.02), ylim = c(-0.02,1.02)) +
        theme_classic() +
        theme(panel.border = element_rect(fill = NA, color = "black",
            size = 1, linetype = 1)) +
        theme(axis.text.y = element_text(size = 18, color = "black"),
            axis.title = element_text(face = "plain", size = 20)) +
        theme(axis.text.x = element_text(size = 18, color = "black"),
            axis.title = element_text(face = "plain", size = 20)) +
    geom_hline(aes(yintercept = 0.5), color = "black", linetype = 5) +
    geom_vline(aes(xintercept = 0.5), color = "black", linetype = 5) +
    geom_abline(data = data.frame, intercept = c(0, 0), slope = 1) +
  geom_text(data = UNACC, aes(label = row.names(UNACC)), size = 5, nudge_y = 0.04) +
  geom_text(data = TYP1, aes(label = row.names(TYP1)), size = 5, nudge_y = -0.04) +
  geom_text(data = TYP2, aes(label = row.names(TYP2)), size = 5, nudge_y = 0.04) +
  geom_text(data = TYP3, aes(label = row.names(TYP3)), size = 5, nudge_x = -0.07) +
  geom_text(data = TYP4, aes(label = row.names(TYP4)), size = 5, nudge_x = 0.05) +
  geom_text(data = IRR1, aes(label = row.names(IRR1)), size = 5, nudge_y = 0.04) +
  geom_text(data = IRR2a, aes(label = row.names(IRR2a)), size = 5, nudge_y = 0.05, nudge_x = -0.01) +
  geom_text(data = IRR2b, aes(label = row.names(IRR2b)), size = 5, nudge_x = 0.05) +
  geom_text(data = IRR2c, aes(label = row.names(IRR2c)), size = 5, nudge_y = -0.05)
CS

# Save plot as PDF
ggsave("xyplot.pdf", plot = CS, path = NULL, scale = 1,
       width = 11, height = 11, dpi = 300)

# End